/**
 ******************************************************************************
 * @file    bmp280.c
 * @author  Hsiang Hsu, livmee
 * @version V1.0.0
 * @date    2025-05-24
 * @brief   This file contains the c files of template for operation systems.
 ******************************************************************************
 **/

/* Includes ------------------------------------------------------------------*/
#include "bmp280.h"

/* Private typedef -----------------------------------------------------------*/
typedef int32_t BMP280_S32_t;

typedef struct
{
  uint8_t bmp_id;
  uint8_t press_msb;
  uint8_t press_lsb;
  uint8_t press_xlsb;
  uint8_t temp_msb;
  uint8_t temp_lsb;
  uint8_t temp_xlsb;
} BMPOriginalDataTypeDef;
/* Private define ------------------------------------------------------------*/
// 操作 SDI
#define SPI1_MOSI_OUT(n) (n ? LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_7) \
                            : LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_7))
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
// 温度校准系数
static unsigned short dig_T1 = 0;
static signed short dig_T2 = 0;
static signed short dig_T3 = 0;
// 气压校准系数
static unsigned short dig_P1 = 0;
static signed short dig_P2 = 0;
static signed short dig_P3 = 0;
static signed short dig_P4 = 0;
static signed short dig_P5 = 0;
static signed short dig_P6 = 0;
static signed short dig_P7 = 0;
static signed short dig_P8 = 0;
static signed short dig_P9 = 0;
// 校准温度
BMP280_S32_t t_fine;
/* Private function prototypes -----------------------------------------------*/

static void BMPGetCompensationData(void);
static void BMPGetOriginalData(BMPOriginalDataTypeDef *pbuf);
static double bmp280_compensate_T_double(BMP280_S32_t adc_T);
static double bmp280_compensate_P_double(BMP280_S32_t adc_P);
/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
** 名    称 : BMP_Init
** 功    能 : BMP280 初始化（完成 BMP280 寄存器基本配置）
** 入口参数 : 无
** 出口参数 : 无
*******************************************************************************/
static void BMPGetCompensationData(void)
{
  uint8_t lsb = 0x00, msb = 0x00;

  // 读取温度校准系数
  SwapByteSPI1(0xFF, 0x88, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x89, 1, (uint8_t *)&msb);
  dig_T1 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x8A, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x8B, 1, (uint8_t *)&msb);
  dig_T2 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x8C, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x8D, 1, (uint8_t *)&msb);
  dig_T3 = (msb << 8) | lsb;

  // 读取气压校准系数
  SwapByteSPI1(0xFF, 0x8E, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x8F, 1, (uint8_t *)&msb);
  dig_P1 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x90, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x91, 1, (uint8_t *)&msb);
  dig_P2 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x92, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x93, 1, (uint8_t *)&msb);
  dig_P3 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x94, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x95, 1, (uint8_t *)&msb);
  dig_P4 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x96, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x97, 1, (uint8_t *)&msb);
  dig_P5 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x98, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x99, 1, (uint8_t *)&msb);
  dig_P6 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x9A, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x9B, 1, (uint8_t *)&msb);
  dig_P7 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x9C, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x9D, 1, (uint8_t *)&msb);
  dig_P8 = (msb << 8) | lsb;
  SwapByteSPI1(0xFF, 0x9E, 1, (uint8_t *)&lsb);
  SwapByteSPI1(0xFF, 0x9F, 1, (uint8_t *)&msb);
  dig_P9 = (msb << 8) | lsb;
}

/*******************************************************************************
** 名    称 ： BMPGetOriginalData
** 功    能 ： 获取 BMP280 原始数据
** 入口参数 ： pbuf: 存放 BMP280 数据的结构体指针
** 出口参数 ： 无
*******************************************************************************/
static void BMPGetOriginalData(BMPOriginalDataTypeDef *pbuf)
{
  // 读取 BMP280 ID
  SwapByteSPI1(0xFF, 0xD0, 1, &pbuf->bmp_id); // 其实没有必要
  // 读取气压数据
  SwapByteSPI1(0xFF, 0xF7, 1, &pbuf->press_msb);
  SwapByteSPI1(0xFF, 0xF8, 1, &pbuf->press_lsb);
  SwapByteSPI1(0xFF, 0xF9, 1, &pbuf->press_xlsb);
  // 读取温度数据
  SwapByteSPI1(0xFF, 0xFA, 1, &pbuf->temp_msb);
  SwapByteSPI1(0xFF, 0xFB, 1, &pbuf->temp_lsb);
  SwapByteSPI1(0xFF, 0xFC, 1, &pbuf->temp_xlsb);
}
/*******************************************************************************
** 名    称 : bmp280_compensate_T_double
** 功    能 : 官方温度补偿函数，返回补偿后的温度数据（单位：DegC），eg 51.23 即 51.23 DegC
** 入口参数 :
**           adc_T : 温度原始数据
** 出口参数 : 补偿后的温度数据
*******************************************************************************/
static double bmp280_compensate_T_double(BMP280_S32_t adc_T)
{
  double var1, var2, T;
  var1 = (((double)adc_T) / 16384.0 - ((double)dig_T1) / 1024.0) * ((double)dig_T2);
  var2 = ((((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0) *
          (((double)adc_T) / 131072.0 - ((double)dig_T1) / 8192.0)) *
         ((double)dig_T3);
  t_fine = (BMP280_S32_t)(var1 + var2);
  T = (var1 + var2) / 5120.0;
  return T;
}

/*******************************************************************************
** 名    称 : bmp280_compensate_P_double
** 功    能 : 官方气压补偿函数，返回补偿后的气压数据（单位：Pa），eg 96386.2 即 96386.2 Pa = 963.862 hPa
** 入口参数 :
**           adc_P : 气压原始数据
** 出口参数 : 补偿后的气压数据
*******************************************************************************/
static double bmp280_compensate_P_double(BMP280_S32_t adc_P)
{
  double var1, var2, p;
  var1 = ((double)t_fine / 2.0) - 64000.0;
  var2 = var1 * var1 * ((double)dig_P6) / 32768.0;
  var2 = var2 + var1 * ((double)dig_P5) * 2.0;
  var2 = (var2 / 4.0) + (((double)dig_P4) * 65536.0);
  var1 = (((double)dig_P3) * var1 * var1 / 524288.0 + ((double)dig_P2) * var1) / 524288.0;
  var1 = (1.0 + var1 / 32768.0) * ((double)dig_P1);
  if (var1 == 0.0)
  {
    return 0; // avoid exception caused by division by zero
  }
  p = 1048576.0 - (double)adc_P;
  p = (p - (var2 / 4096.0)) * 6250.0 / var1;
  var1 = ((double)dig_P9) * p * p / 2147483648.0;
  var2 = p * ((double)dig_P8) / 32768.0;
  p = p + (var1 + var2 + ((double)dig_P7)) / 16.0;
  return p;
}
/* Public functions ----------------------------------------------------------*/

/*******************************************************************************
** 名    称 : BMP_Init
** 功    能 : BMP280 初始化（完成 BMP280 寄存器基本配置）
** 入口参数 : 无
** 出口参数 : 无
*******************************************************************************/
void BMP_Init(void)
{
  // 【TODO】：BMP280 初始化
  uint8_t rx_buf = 0x00;
  // 1. 读取 BMP280 ID
  SwapByteSPI1(0x00, 0xD0, 0, &rx_buf);
  // 【TODO】 2. 进行 ID 校验
  // 3. 读取 BMP280 校准数据
  BMPGetCompensationData();
  //  0xF4 “ctrl_meas”
  int i = 0;
  //  0xF5 “config”
  //
}

/*******************************************************************************
** 名    称 : SwapByteSPI1
** 功    能 : SPI1 数据交换(只交换 1 Byte)，在本模块上，SPI1 用于连接 BMP280
** 入口参数 :
**           tx_data : 数据, 0xFF 如果不需要发送数据 (1 Byte)
**           addr : 寄存器地址(1 Byte)
**           rwflag : 读写标志(1:读，0:写)
**           rx_buf : 接收数据缓存(1 Byte)
** 出口参数 : 无
*******************************************************************************/
void SwapByteSPI1(uint8_t tx_data, uint8_t addr, uint8_t rwflag, uint8_t *rx_buf)
{
  // 【TODO】：使用结构体封装
  uint8_t tx = 0;
  uint8_t rx = 0;
  // 准备时钟线
  LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_5);
  // 片选 BMP280
  LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4);
  // 待访问地址
  tx = rwflag << 7 | addr; // 读写标志位 | 地址
  for (uint8_t i = 0; i < 8; i++)
  {
    // 将 SCK 拉低
    LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
    // 单片机发送 bit，操作 MOSI，高位优先
    SPI1_MOSI_OUT((tx & 0x80));
    tx <<= 1;
    // 等待 BMP280 发送
    LL_uDelay(10);
    // 将 SCK 拉高
    LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
    // 等待 BMP280 接收
    LL_uDelay(10);
  }

  // 待发送数据
  tx = tx_data;
  for (uint8_t i = 0; i < 8; i++)
  {
    // 操作 SDI，高位优先：tx_buf & (0x80 >> i)
    SPI1_MOSI_OUT((tx & 0x80));
    tx <<= 1;
    // 将 SCK 拉低
    LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
    // 等待 BMP280 发送
    LL_uDelay(10);
    // 读取 SDO
    rx <<= 1;
    rx |= LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_6);
    // 将 SCK 拉高
    LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
    // 等待 BMP280 接收
    LL_uDelay(10);
  }
  // 发送完毕，取消片选
  LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4);
  LL_uDelay(10); // 控制两次发送的间隔
  // 返回数据
  *rx_buf = rx;
  // 【TODO】：状态返回
  // 【TODO】：安全措施
  // 【TODO】：使用 Delay 不好，可以优化
}

/*******************************************************************************
** 名    称 ： BMPGetData
** 功    能 ： 获取 BMP280 数据(Pa, degC)，内部调用了 BMP_Init()，但建议注释掉
** 入口参数 ： pbuf: 存放 BMP280 数据的结构体指针（BMP280_Data_t*）
** 出口参数 ： 无
*******************************************************************************/
void BMPGetData(BMP280_Data_t *pbuf)
{
  // 1. 初始化 BMP280
  // BMP_Init(); //建议手动在 main.c 中调用，这里做个防范
  // 2. 获取 BMP280 原始数据
  BMPOriginalDataTypeDef org_data = {0};
  BMPGetOriginalData(&org_data);
  BMP280_S32_t adc_T = ((BMP280_S32_t)org_data.temp_msb << 12) | ((BMP280_S32_t)org_data.temp_lsb << 4) | (org_data.temp_xlsb >> 4);
  BMP280_S32_t adc_P = ((BMP280_S32_t)org_data.press_msb << 12) | ((BMP280_S32_t)org_data.press_lsb << 4) | (org_data.press_xlsb >> 4);
  // 3. 解析温度
  pbuf->temperature = bmp280_compensate_T_double(adc_T);
  // 4. 解析气压
  pbuf->pressure = bmp280_compensate_P_double(adc_P);
}
/********************************END OF FILE***********************************/

//【TODO】：移植整数型版本的 BMP280 补偿函数
// // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
// // t_fine carries fine temperature as global value
// BMP280_S32_t t_fine;
// BMP280_S32_t bmp280_compensate_T_int32(BMP280_S32_t adc_T)
// {
// BMP280_S32_t var1, var2, T;
// var1 = ((((adc_T>>3) - ((BMP280_S32_t)dig_T1<<1))) * ((BMP280_S32_t)dig_T2)) >> 11;
// var2 = (((((adc_T>>4) - ((BMP280_S32_t)dig_T1)) * ((adc_T>>4) - ((BMP280_S32_t)dig_T1))) >> 12) *
// ((BMP280_S32_t)dig_T3)) >> 14;
// t_fine = var1 + var2;
// T = (t_fine * 5 + 128) >> 8;
// return T;
// }
// // Returns pressure in Pa as unsigned 32 bit integer. Output value of “96386” equals 96386 Pa = 963.86 hPa
// BMP280_U32_t bmp280_compensate_P_int32(BMP280_S32_t adc_P)
// {
// BMP280_S32_t var1, var2;
// BMP280_U32_t p;
// var1 = (((BMP280_S32_t)t_fine)>>1) - (BMP280_S32_t)64000;
// var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((BMP280_S32_t)dig_P6);
// var2 = var2 + ((var1*((BMP280_S32_t)dig_P5))<<1);
// var2 = (var2>>2)+(((BMP280_S32_t)dig_P4)<<16);
// var1 = (((dig_P3 * (((var1>>2) * (var1>>2)) >> 13 )) >> 3) + ((((BMP280_S32_t)dig_P2) * var1)>>1))>>18;
// var1 =((((32768+var1))*((BMP280_S32_t)dig_P1))>>15);
// if (var1 == 0)
// {
// return 0; // avoid exception caused by division by zero
// }
// p = (((BMP280_U32_t)(((BMP280_S32_t)1048576)-adc_P)-(var2>>12)))*3125;
// if (p < 0x80000000)
// {
// p = (p << 1) / ((BMP280_U32_t)var1);
// }
// else
// {
// p = (p / (BMP280_U32_t)var1) * 2;
// }
// var1 = (((BMP280_S32_t)dig_P9) * ((BMP280_S32_t)(((p>>3) * (p>>3))>>13)))>>12;
// var2 = (((BMP280_S32_t)(p>>2)) * ((BMP280_S32_t)dig_P8))>>13;
// p = (BMP280_U32_t)((BMP280_S32_t)p + ((var1 + var2 + dig_P7) >> 4));
// return p;
// }